import os
import sys
import dbus.service
import gobject
import thread

from dbus.mainloop.glib import DBusGMainLoop
from xml.dom import minidom

class ServicePool:
    servicesInfoList = []
    def addService(serviceType,  serviceUrl,  serviceId):
        ServicePool.servicesInfoList.append((serviceType,  serviceUrl,  serviceId))
    addService = staticmethod(addService)
    def getServiceInfoList():
        return ServicePool.servicesInfoList
    getServiceInfoList = staticmethod(getServiceInfoList)

class RemoteObjectSkeletonProvider:
    
    def createProvider(confContext,  name,  seq=None):
        if name == "dbus":
            return DBusRemoteObjectSkeletonProvider(confContext,  seq)
    createProvider = staticmethod(createProvider)
    
    def deploy(self,  serviceType,  serviceModule):
        pass
    
    def start(self):
        pass

class DBusRemoteObjectSkeletonProvider(RemoteObjectSkeletonProvider):
    
    def __init__(self,  confContext,  seq=None):
        registry_file_path = os.path.join(confContext.getConfRootPath(),  "dbus_wrapper_mappings.xml")
        xmldoc = minidom.parse(registry_file_path)
        self.__mappings = {}
        entries = xmldoc.getElementsByTagName("dbus_wrapper")
        for entry in entries:
            type = int(entry.getElementsByTagName("service-type")[0].firstChild.data)
            class_name = entry.getElementsByTagName("server-class-name")[0].firstChild.data
            self.__mappings[type] = class_name
            
        DBusGMainLoop(set_as_default=True)
        if seq is not None:
            self.__bus = dbus.service.BusName("laf.socf%s" % seq, bus=dbus.SessionBus())
        else:
            self.__bus = dbus.service.BusName("laf.socf", bus=dbus.SessionBus())
        self.__loop = gobject.MainLoop()
        
    def start(self):
        self.__loop.run()

    def __getClassByType(self,  type):
        name = self.__mappings[type]
        module = sys.modules["socf.server.remote"]
        class_type = getattr(module,  name)
        return class_type

    def deploy(self,  serviceType,  serviceModule):
        classType = self.__getClassByType(serviceType)
        remoteObject = classType(self.__bus,  serviceModule)
        serviceId = ""
        if serviceModule.getDriver() != None:
            serviceId = serviceModule.getDriver().getDeviceId()
        ServicePool.addService(serviceType,  remoteObject.getServiceURI(),  serviceId)
    
class DBusWrapperBase:
    
    def getServiceURI(self):
        pass
    
    def createURI(self,  busName,  servicePath):
        return "dbus:%s%s" % (busName,  servicePath)
    
class DBusGpsServiceWrapper(DBusWrapperBase,  dbus.service.Object):
    
    def __init__(self, bus,  serviceModule):
        self.__serviceModule = serviceModule
        objectPath = "/server/%s" % serviceModule.getDriver().getDeviceId()
        dbus.service.Object.__init__(self, bus, objectPath)
        self.__serviceURI = self.createURI(bus.get_name(),  objectPath)

    def getServiceURI(self):
        return self.__serviceURI

    @dbus.service.method('socf.getLocation')
    def getLocation(self):
        return self.__serviceModule.getLocation()

class DBusSonarServiceWrapper(DBusWrapperBase,  dbus.service.Object):
    
    def __init__(self, bus,  serviceModule):
        self.__serviceModule = serviceModule
        objectPath = "/server/%s" % serviceModule.getDriver().getDeviceId()
        dbus.service.Object.__init__(self, bus, objectPath)
        self.__serviceURI = self.createURI(bus.get_name(),  objectPath)

    def getServiceURI(self):
        return self.__serviceURI

    @dbus.service.method('socf.getDistance')
    def getDistance(self):
        return self.__serviceModule.getDistance()

class DBusCompassServiceWrapper(DBusWrapperBase,  dbus.service.Object):
    
    def __init__(self, bus,  serviceModule):
        self.__serviceModule = serviceModule
        objectPath = "/server/%s" % serviceModule.getDriver().getDeviceId()
        dbus.service.Object.__init__(self, bus, objectPath)
        self.__serviceURI = self.createURI(bus.get_name(),  objectPath)

    def getServiceURI(self):
        return self.__serviceURI

    @dbus.service.method('socf.getDirection')
    def getDirection(self):
        return self.__serviceModule.getDirection()
        
class DBusMetalDetectorServiceWrapper(DBusWrapperBase,  dbus.service.Object):
    
    def __init__(self, bus,  serviceModule):
        self.__serviceModule = serviceModule
        objectPath = "/server/%s" % serviceModule.getDriver().getDeviceId()
        dbus.service.Object.__init__(self, bus, objectPath)
        self.__serviceURI = self.createURI(bus.get_name(),  objectPath)

    def getServiceURI(self):
        return self.__serviceURI

    @dbus.service.method('socf.getMines')
    def getMines(self):
        return self.__serviceModule.getMines()
    
class DBusNavServiceWrapper(DBusWrapperBase,  dbus.service.Object):
    
    def __init__(self, bus,  serviceModule):
        self.__serviceModule = serviceModule
        objectPath = "/server/%s" % serviceModule.getDriver().getDeviceId()
        dbus.service.Object.__init__(self, bus, objectPath)
        self.__serviceURI = self.createURI(bus.get_name(),  objectPath)

    def getServiceURI(self):
        return self.__serviceURI

    @dbus.service.method('socf.moveUp')
    def moveUp(self):
        self.__serviceModule.moveUp()

    @dbus.service.method('socf.moveDown')
    def moveDown(self):
        self.__serviceModule.moveDown()
    
    @dbus.service.method('socf.moveLeft')
    def moveLeft(self):
        self.__serviceModule.moveLeft()
    
    @dbus.service.method('socf.moveRight')
    def moveRight(self):
        self.__serviceModule.moveRight()
    
    @dbus.service.method('socf.setSpeed')
    def setSpeed(self, speed):
        self.__serviceModule.setSpeed()
        
    @dbus.service.method('socf.stop')
    def stop(self):
        self.__serviceModule.stop()

class DBusDiscoveryServiceWrapper(DBusWrapperBase,  dbus.service.Object):
    
    def __init__(self, bus,  serviceModule):
        self.__serviceModule = serviceModule
        objectPath = '/server/discoveryService'
        dbus.service.Object.__init__(self, bus, objectPath)
        self.__serviceURI = self.createURI(bus.get_name(),  objectPath)

    def getServiceURI(self):
        return self.__serviceURI

    @dbus.service.method('socf.getCurrentServicesList')
    def getCurrentServicesList(self):
        return self.__serviceModule.getCurrentServicesList()
